package com.example.mallorder.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.utils.PageUtils;
import com.common.utils.Query;
import com.common.utils.R;
import com.common.vo.MemberVO;
import com.common.vo.OrderItemVO;
import com.common.vo.WareSkuLockVO;
import com.example.mallorder.config.OrderHandleInterceptor;
import com.example.mallorder.constant.OrderConstant;
import com.example.mallorder.controller.vo.CartItemVO;
import com.example.mallorder.controller.vo.MemberAddressVO;
import com.example.mallorder.controller.vo.OrderConfirmVO;
import com.example.mallorder.controller.vo.OrderItemSpuInfoVO;
import com.example.mallorder.controller.vo.OrderResponseVO;
import com.example.mallorder.controller.vo.OrderSubmitVO;
import com.example.mallorder.dao.OrderDao;
import com.example.mallorder.dto.OrderCreateTO;
import com.example.mallorder.entity.OrderEntity;
import com.example.mallorder.entity.OrderItemEntity;
import com.example.mallorder.fegin.CartFeginService;
import com.example.mallorder.fegin.MemberFeginService;
import com.example.mallorder.fegin.ProductFeginService;
import com.example.mallorder.fegin.WareFeignService;
import com.example.mallorder.service.OrderItemService;
import com.example.mallorder.service.OrderService;
import com.example.mallorder.util.OrderMsgProducer;
import com.exception.NoStockExecption;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10,
            10, TimeUnit.SECONDS, new LinkedBlockingQueue(100),
            Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    @Autowired
    RedisTemplate redisTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Autowired
    private MemberFeginService memberFeginService;
    @Autowired
    private CartFeginService cartFeginService;

    @Override
    public OrderConfirmVO confirmOrder() {
        OrderConfirmVO vo = new OrderConfirmVO();
        MemberVO memberVO = (MemberVO) OrderHandleInterceptor.threadLocal.get();
        // 获取到 RequestContextHolder 的相关信息
        //异步处理的时候我们需要从主线程中获取Request信息，然后绑定在子线程中
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
        // 同步主线程中的 RequestContextHolder
        RequestContextHolder.setRequestAttributes(requestAttributes);
        // 1.查询当前登录用户对应的会员的地址信息
        Long id = memberVO.getId();
        List<MemberAddressVO> addresses = memberFeginService.getAddress(id);
        vo.setAddress(addresses);
//        }, threadPoolExecutor);
//        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
        RequestContextHolder.setRequestAttributes(requestAttributes);
        // 2.查询购物车中选中的商品信息
        List<CartItemVO> userCartItems = cartFeginService.getUserCartItems();
        vo.setItems(userCartItems);
//        }, threadPoolExecutor);
        try {
//            CompletableFuture.allOf(future1, future2).get();
        } catch (Exception e) {
            System.out.println(e);
            e.printStackTrace();
        }
        // 3.计算订单的总金额和需要支付的总金额 VO自动计算

        // 4.生成防重的Token
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        // 我们需要把这个Token信息存储在Redis中
        // order:token:用户编号
        redisTemplate.opsForValue().set("order:token" + ":" + memberVO.getId(), token);
        // 然后我们需要将这个Token绑定在响应的数据对象中
        vo.setOrderToken(token);
        return vo;
    }

    ReentrantLock lock = new ReentrantLock();

    @GlobalTransactional
    @Override
    public OrderResponseVO orderService(OrderSubmitVO orderSubmitVO) {

        // 需要返回响应的对象
        OrderResponseVO responseVO = new OrderResponseVO();

        // 获取当前登录的用户信息
        MemberVO memberVO = (MemberVO) OrderHandleInterceptor.threadLocal.get();
        // 1.验证是否重复提交  保证Redis中的token 的查询和删除是一个原子性操作
        String key = "order:token" + ":" + memberVO.getId();

//        lock.lock();//加锁
//        try {
//            String redisToken = (String) redisTemplate.opsForValue().get(key);
//            if(redisToken != null && redisToken.equals(orderSubmitVO.getOrderToken())) {
//                // 表示是第一次提交
//                // 需要删除Token
//                redisTemplate.delete(key);
//            }
//        }catch (Exception e){
//            return responseVO;
//        } finally{
//            lock.unlock();
//        }

        String script = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Long result = (Long) redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
                Arrays.asList(key),
                orderSubmitVO.getOrderToken());

        if (result == 0) {
            // 表示验证失败 说明是重复提交
            return responseVO;
        }

        // 2.创建订单和订单项信息
        OrderCreateTO orderCreateTO = createOrder(orderSubmitVO);
        responseVO.setOrderEntity(orderCreateTO.getOrderEntity());
        // 3.保存订单信息
        saveOrder(orderCreateTO);

        // 4.锁定库存信息
        // 订单号  SKU_ID  SKU_NAME 商品数量
        // 封装 WareSkuLockVO 对象
        lockWareSkuStock(responseVO, orderCreateTO);

//        int aa=1/0;

        // 5.同步更新用户的会员积分
        // int i = 1 / 0;
        // 订单成功后需要给 消息中间件发送延迟30分钟的关单消息
        orderMsgProducer.sendOrderMsg(orderCreateTO.getOrderEntity().getOrderSn());
        return responseVO;
    }

    @Autowired
    private OrderMsgProducer orderMsgProducer;

    @Autowired
    private OrderItemService orderItemService;

    private void saveOrder(OrderCreateTO orderCreateTO) {
        // 1.订单数据
        OrderEntity orderEntity = orderCreateTO.getOrderEntity();
        this.save(orderEntity);
        // 2.订单项数据
        List<OrderItemEntity> orderItemEntitys = orderCreateTO.getOrderItemEntitys();
        orderItemService.saveBatch(orderItemEntitys);
    }

    /**
     * 创建订单头
     *
     * @param orderSubmitVO
     * @return
     */
    private OrderEntity buildOrder(OrderSubmitVO orderSubmitVO) {
        OrderEntity orderEntity = new OrderEntity();
        String orderNum = IdWorker.getIdStr();
        orderEntity.setOrderSn(orderNum);
        MemberVO memberVO = OrderHandleInterceptor.threadLocal.get();
//        会员信息
        orderEntity.setMemberId(memberVO.getId());
        orderEntity.setMemberUsername(memberVO.getUsername());

        // 根据收获地址ID获取收获地址的详细信息
        MemberAddressVO memberAddressVO = memberFeginService.getAddressById(orderSubmitVO.getAddrId());

        orderEntity.setReceiverCity(memberAddressVO.getCity());
        orderEntity.setReceiverDetailAddress(memberAddressVO.getDetailAddress());
        orderEntity.setReceiverName(memberAddressVO.getName());
        orderEntity.setReceiverPhone(memberAddressVO.getPhone());
        orderEntity.setReceiverPostCode(memberAddressVO.getPostCode());
        orderEntity.setReceiverRegion(memberAddressVO.getRegion());
        orderEntity.setReceiverProvince(memberAddressVO.getProvince());
        // 设置订单的状态 待付款
        orderEntity.setStatus(OrderConstant.OrderStateEnum.FOR_THE_PAYMENT.getCode());

        return orderEntity;
    }

    @Autowired
    private ProductFeginService productFeginService;


    /**
     * 创建订单的方法
     *
     * @param vo
     * @return
     */
    private OrderCreateTO createOrder(OrderSubmitVO vo) {
        OrderCreateTO createTO = new OrderCreateTO();
        // 创建订单
        OrderEntity orderEntity = buildOrder(vo);
        createTO.setOrderEntity(orderEntity);
        // 创建OrderItemEntity 订单项
        List<OrderItemEntity> orderItemEntitys = buildOrderItems(orderEntity.getOrderSn());
        createTO.setOrderItemEntitys(orderItemEntitys);
        return createTO;
    }

    /**
     * 通过购物车中选中的商品来创建对应的购物项信息
     *
     * @return
     */
    private List<OrderItemEntity> buildOrderItems(String orderSN) {
        List<OrderItemEntity> orderItemEntitys = new ArrayList<>();
        // 获取购物车中的商品信息 选中的
        List<CartItemVO> userCartItems = cartFeginService.getUserCartItems();
        if (userCartItems != null && userCartItems.size() > 0) {
            // 统一根据SKUID查询出对应的SPU的信息
            List<Long> spuIds = new ArrayList<>();
            for (CartItemVO cartItemVO : userCartItems) {
                if (!spuIds.contains(cartItemVO.getSpuId())) {
                    spuIds.add(cartItemVO.getSpuId());
                }
            }
            // 远程调用商品服务获取到对应的SPU信息
            List<Long> spuIdList = spuIds.stream().map(spuId -> {
                return spuId.longValue();
            }).collect(Collectors.toList());
            List<OrderItemSpuInfoVO> spuInfos = productFeginService.getOrderItemSpuInfoBySpuId(spuIdList);
            Map<Long, OrderItemSpuInfoVO> map = spuInfos.stream().collect(Collectors.toMap(OrderItemSpuInfoVO::getId, item -> item));
            for (CartItemVO cartItemVO : userCartItems) {
                // 获取到商品信息对应的 SPU信息
                OrderItemSpuInfoVO spuInfo = map.get(cartItemVO.getSpuId());
                OrderItemEntity orderItemEntity = buildOrderItem(cartItemVO, spuInfo);
                // 绑定对应的订单编号
                orderItemEntity.setOrderSn(orderSN);
                orderItemEntitys.add(orderItemEntity);
            }
        }

        return orderItemEntitys;
    }

    /**
     * 根据一个购物车中的商品创建对应的 订单项
     *
     * @param userCartItem
     * @return
     */
    private OrderItemEntity buildOrderItem(CartItemVO userCartItem, OrderItemSpuInfoVO spuInfo) {
        OrderItemEntity entity = new OrderItemEntity();
        // SKU信息
        entity.setSkuId(userCartItem.getSkuId());
        entity.setSkuName(userCartItem.getTitle());
        entity.setSkuPic(userCartItem.getImage());
        entity.setSkuQuantity(userCartItem.getCount());
        List<String> skuAttr = userCartItem.getSkuAttr();
        String skuAttrStr = StringUtils.collectionToDelimitedString(skuAttr, ";");
        entity.setSkuAttrsVals(skuAttrStr);
        // SPU信息
        entity.setSpuId(spuInfo.getId());
        entity.setSpuBrand(spuInfo.getBrandName());
        entity.setCategoryId(spuInfo.getCatalogId());
        entity.setSpuPic(spuInfo.getImg());
        // 优惠信息 忽略
        // 积分信息
        entity.setGiftGrowth(userCartItem.getPrice().intValue());
        entity.setGiftIntegration(userCartItem.getPrice().intValue());
        entity.setSkuPrice(userCartItem.getPrice());
        return entity;
    }

    @Autowired
    WareFeignService wareFeignService;


    private void lockWareSkuStock(OrderResponseVO responseVO, OrderCreateTO orderCreateTO) throws NoStockExecption {
        WareSkuLockVO wareSkuLockVO = new WareSkuLockVO();
        wareSkuLockVO.setOrderSN(orderCreateTO.getOrderEntity().getOrderSn());
        List<OrderItemVO> orderItemVos = orderCreateTO.getOrderItemEntitys().stream().map(item -> {
            OrderItemVO itemVo = new OrderItemVO();
            itemVo.setSkuId(item.getSkuId());
            itemVo.setTitle(item.getSkuName());
            itemVo.setCount(item.getSkuQuantity());
            return itemVo;
        }).collect(Collectors.toList());
        wareSkuLockVO.setItems(orderItemVos);
        // 远程锁库存的操作
        R r = wareFeignService.orderLockStock(wareSkuLockVO);
        if (r.getCode() == 0) {
            // 表示锁定库存成功
            responseVO.setCode(0); // 表示 创建订单成功
        } else {
            // 表示锁定库存失败
            responseVO.setCode(2); // 表示库存不足，锁定失败
            throw new NoStockExecption(10000L);
        }
    }
}